會員系統的部分,我們已經完成第一部分「會員註冊」的功能了。接續往「會員登入」的功能出發。
$ npm install jsonwebtoken
在models
資料夾新增個login_model.js
的檔案。
.
├── app.js
├── bin
│ └── www
├── config
│ └── development_config.js
├── controllers
│ └── modify_controller.js
├── models
│ ├── connection_db.js
│ ├── encryption_model.js
│ ├── login_model.js
│ └── register_model.js
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── member.js
│ └── users.js
├── sevice
│ └── member_check.js
├── views
├── error.ejs
└── index.ejs
├── .env
└── .gitignore
看到需求後,我們可以預估大概需要做到下列幾個事項:
為了驗證帳號密碼是否正確,這意謂著我們要先把client端的資料取出,並將取出的資料與資料庫的資料做比對。先修改在models
資料夾中的login_model.js
檔案。
const db = require('./connection_db');
module.exports = function memberLogin(memberData) {
let result = {};
return new Promise((resolve, reject) => {
// 找尋
db.query('SELECT * FROM member_info WHERE email = ? AND password = ?', [memberData.email, memberData.password], function (err, rows) {
if (err) {
result.status = "登入失敗。"
result.err = "伺服器錯誤,請稍後在試!"
reject(result);
return;
}
resolve(rows);
});
});
}
之後,接續修改在controllers
資料夾中的modify_controller.js
檔案。我們先新增一個function,而這個function是專門處理login
的動作。
loginAction(memberData).then(rows => {
if (check.checkNull(rows) === true) {
res.json({
result: {
status: "登入失敗。",
err: "請輸入正確的帳號或密碼。"
}
})
} else if (check.checkNull(rows) === false) {
res.json({
result: {
status: "登入成功。",
loginMember: "歡迎 " + rows[0].name + " 的登入!",
}
})
}
})
當中check的checkNull
,則是我們在service
資料夾的member_check.js
檔案中新增了一個可以辨識空值的判斷:
//判斷空值
checkNull(data) {
for (var key in data) {
// 不為空
return false;
}
// 為空值
return true;
}
最後,修改routes
資料夾的member.js
檔案。新增一個API URL為/login
給登入這功能專用。
var express = require('express');
var router = express.Router();
const MemberModifyMethod = require('../controllers/modify_controller');
memberModifyMethod = new MemberModifyMethod();
router.post('/register', memberModifyMethod.postRegister);
router.post('/login', memberModifyMethod.postLogin);
module.exports = router;
我們一樣透過Postman來幫我們做測試:
其結果:
接續測試錯誤的密碼試試看:
其結果:
Token部分我們需要用到前面所提到套件jsonwebtoken
,透過它來幫我們產生token。由於token可以設置時間限制,也就是時間一到就會過期。而這次的範例中,我們先使用1小時作為一個期限,並將使用者的id資料也跟著放進去token的生成規則中。最後,再把token的值塞入response的header中,且取名為token
。
首先,我們先修改Node.js-Backend見聞錄(12):實作-會員系統(一)-會員註冊(一)中提到的config
資料夾的development_config.js
檔案。
註記:這是因為我們在 token 部分接續會使用到 secret。而 secret 算是敏感性資料之一。所以我們會搭配
.env
的檔案來將環境變數藏匿於該檔案中。
require('dotenv').config()
module.exports = {
mysql: {
host: process.env.HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
},
secret: process.env.MY_SECRET
}
並接續修改.env
檔案,將MY_SECRET
放置其中。
HOST = 'localhost'
DATABASE_USER = 'test'
DATABASE_PASSWORD = '1234'
DATABASE = 'member'
MY_SECRET = 'secret'
最後再修改controllers
資料夾的modify_controller.js
檔案:
loginAction(memberData).then(rows => {
if (check.checkNull(rows) === true) {
res.json({
result: {
status: "登入失敗。",
err: "請輸入正確的帳號或密碼。"
}
})
} else if (check.checkNull(rows) === false) {
// 產生token
const token = jwt.sign({
algorithm: 'HS256',
exp: Math.floor(Date.now() / 1000) + (60 * 60), // token一個小時後過期。
data: rows[0].id
}, config.secret);
res.setHeader('token', token);
res.json({
result: {
status: "登入成功。",
loginMember: "歡迎 " + rows[0].name + " 的登入!",
}
})
}
})
註記:將會員的id放進去token的生成規則中,這步驟是為了在下個實作「會員資料」中,如果會員想修改自己的資料,可以根據token來反推出是哪個會員的id,透過這個id就能指定資料庫要修改哪筆會員資料。
我們一樣透過Postman來幫我們做測試:
其結果:
我們就能看到產生出來的token
就藏在response的headers的token
欄位中。
這在我們已經完成了「會員登入」的功能了,接下來會往「修改會員資料」部分前進。